// =====================================================================================
// 
//       Filename:  media.c
// 
//    Description:  un semplice programma per gestire e calcolare la media pesata dei voti.
// 
//        Version:  1.0
//        Created:  01/03/2012 19:53:34
//       Revision:  none
//       Compiler:  g++
// 
//         Author:  Daniele Taufer (), teodida@gmail.com
//        Company:  
// 
// =====================================================================================

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

typedef struct esame{
    char nome[32];
    int voto;
    int cfu;
    char lode;
    char interno;
    struct esame* next;
} esame;

typedef esame* lista;

lista crealista(){
    return NULL;
}

lista leggidafile(FILE *f){
    char nome[32];
    fscanf(f, " %s", nome);
    if(!strcmp(nome,"@")) return NULL;
    lista new = malloc(sizeof(esame));
    strcpy(new->nome, nome);
    fscanf(f, " %d %d %c %c", &new->cfu, &new->voto, &new->lode, &new->interno);
    new->next = leggidafile(f);        
    return new;
}

int doppio(lista l, char nome[32]){
    if(l == NULL) return 0;
    if(!strcmp(l->nome, nome)) return 1;
    return doppio(l->next, nome);
}

lista aggiungiesame(lista l){
    char nome[32];
    printf("Inserisci il nome dell'esame: ");
    scanf(" %s", nome);
    if(doppio(l, nome)){
        printf("Esame gia' presente nella lista!\n");
        return l;
    }
    lista new = malloc(sizeof(esame));
    strcpy(new->nome, nome);
    printf("Inserisci il numero di CFU dell'esame: ");
    scanf(" %d", &new->cfu);
    do{
    printf("Inserisci il risultato ottenuto: ");
    scanf(" %d", &new->voto);
    }while(new->voto > 30 || new-> voto < 0);
    if(new->voto == 30){
        do{
            printf("Lode? (s/n): ");
            scanf(" %c", &new->lode);
        }while(new->lode != 's' && new->lode != 'n'); 
    }
    else new->lode = 'n';
    do{
        printf("Era un esame interno? (s/n): ");
        scanf(" %c", &new->interno); 
    }while(new->interno != 's' && new-> interno != 'n');
    printf("Esame correttamente inserito\n");
    new->next = l;
    return new;
}

int lunghezza(lista l){
    if(l == NULL) return 0;
    return 1 + lunghezza(l->next);
}

void stampaesame(lista l){
    printf("%-15s\t%d\t\t%d", l->nome, l->cfu, l->voto);
    if(l->lode == 's')
        printf(" L");
    printf("\t\t");
    if(l->interno == 's')
        printf("(I)\n");
    else printf("(E)\n");
    return;
}  

void stampa(lista l){
    if(l == NULL) return;
    stampaesame(l);
    stampa(l->next);
}

void stampasufile(lista l, FILE *f){
    if(l == NULL){
        fprintf(f, "@");
        return; 
    }
    fprintf(f, "%s %d %d %c %c\n", l->nome, l->cfu, l->voto, l->lode, l->interno);
    stampasufile(l->next, f); 
}

float somma(lista l, int x){
    if(l == NULL) return 0;
    if(x == 0) return l->voto * l-> cfu + somma(l->next, x);
    if(x == 1)
    {
        if(l->interno == 's') return l->voto * l-> cfu + somma(l->next, x); 
        else return somma(l->next, x);
    }
    if(x == 2)
    {
        if(l->interno == 'n') return l->voto * l-> cfu + somma(l->next, x); 
        else return somma(l->next, x); 
    }
}

int sommacfu(lista l, int x){
    if(l == NULL) return 0; 
    if(x == 0){
        return l->cfu + sommacfu(l->next, x);  
    }
    if(x == 1){
        if(l->interno == 's') return l->cfu + sommacfu(l->next, x);
        else return sommacfu(l->next, x);
    }
    if(x == 2){
        if(l->interno == 'n') return l->cfu + sommacfu(l->next, x);
        else return sommacfu(l->next, x);
    }  
}

float calcolamedia(lista l, int x){
    float sum = somma(l, x);
    int sumcfu = sommacfu(l, x);
    return sum / sumcfu;
}

int contalodi(lista l, int x){
    if(l == NULL) return 0;
    if(x == 0){
        if(l->lode == 's') return 1 + contalodi(l->next, 0);
        else return contalodi(l->next, 0);
    }
    if(x == 1){
        if(l->lode == 's' && l->interno == 's') return 1 + contalodi(l->next, 1);
        else return contalodi(l->next, 1); 
    }
    if(x == 2){
        if(l->lode == 's' && l->interno == 'n') return 1 + contalodi(l->next, 2);
        else return contalodi(l->next, 2);  
    }
}

lista cercanome(lista l, char nome[32]){
    if(l == NULL) return NULL;
    if(!strcmp(l->nome, nome)) return l;
    return cercanome(l-> next, nome);
}

lista cercavoto(lista l, int voto){
    if(l == NULL) return NULL;
    if(l->voto == voto) return l;
    return cercavoto(l-> next, voto);  
}

lista cercacfu(lista l, int cfu){
    if(l == NULL) return NULL;
    if(l->cfu == cfu) return l;
    return cercacfu(l-> next, cfu); 
}

lista cercalodi(lista l){
    if(l == NULL) return NULL;
    if(l->lode == 's') return l;
    return cercalodi(l-> next);
}

lista elimina(lista l, lista eliminato){
    if(l == eliminato){
        lista ritornare = l->next;
        free(l);
        return ritornare;
    }
    if(l->next == eliminato){
        l->next = eliminato->next;
        free(eliminato);
        return l;
    }
    l->next = elimina(l->next, eliminato);
    return l;
}

void libera(lista l){
    if(l == NULL)
        return;
    libera(l->next);
    free(l);
}

main(){
    printf("\n\t\t\tCalcolatore media pesata, ver.1.0\n\n");
    char scelta = '0';
    int continua = 1;
    char nome_esame[32];
    int risultato;
    int peso;
    float media;
    char eliminato[32];
    int nlodi;
    int i;
    lista puntalista;
    while(scelta != '1' && scelta != '2')
    {
        printf("Se e' la prima volta che usi il calcolatore media pesata devi inizializzarlo affinche' funzioni.\nATTENZIONE: inizializzando il programma tutti i dati precedentemente salvati andranno persi!\n\t1 - Inizializza\n\t2 - Lancia il programma\n");
    scanf(" %c", &scelta); 
    }
    if(scelta == '1'){
        FILE *f = fopen("voti.txt", "w");
        fprintf(f, "@\n");
        fclose(f);  
    }
    FILE *f = fopen("voti.txt", "r");
    lista data = crealista();
    data = leggidafile(f);
    fclose(f);
    int lun = lunghezza(data);
    printf("Fino ad ora hai inserito %d voti.\n", lun);
    while(continua)
    {
        lun = lunghezza(data);
        printf("\n Scegli l'opzione corrispondente:\n1 - Inserisci esame\n");
        if(lun) 
            printf("2 - Visualizza lista esami\n3 - Modifica lista esami\n4 - Cerca esame\n5 - Calcola media\n");
        printf("Q - Esci\n");
        scanf(" %c", &scelta);
        if(lun == 0 && (scelta != '1' && scelta != 'q' && scelta != 'Q')){
            printf("Scelta non valida.\n");
            continue;
        }
    switch(scelta){
        case '1':
            {
                data = aggiungiesame(data);
                FILE *f = fopen("voti.txt", "w");
                stampasufile(data, f);
                fclose(f);
                break;
            }
        case '2':
            {
                printf("ESAME:\t\tCFU:\t\tVOTO:\t\tInterno/Esterno\n");
                stampa(data);
                break;
            }
        case '3':
            {
                do{
                    printf("Cosa vuoi fare?\n1 - Elimina esame\n2 - Ordina esami\n");
                scanf(" %c", &scelta); 
                }while(scelta != '1' && scelta != '2');
                switch(scelta){
                    case '1':
                        {
                            printf("Inserisci il nome dell'esame che vuoi eliminare\n");
                            scanf(" %s", eliminato);
                            puntalista = cercanome(data, eliminato);
                            if(puntalista == NULL) 
                            {
                                printf("Nessun esame con questo nome e' presente nella lista.\n");
                                continue;
                            }
                            printf("Vuoi eliminare %s (voto: %d, cfu:%d)? (s/n)\n", puntalista->nome, puntalista->voto, puntalista->cfu);
                            scanf(" %c", &scelta);
                            if(scelta == 's' || scelta == 'S')
                            {
                                data = elimina(data, puntalista);
                                FILE *f = fopen("voti.txt", "w");
                                stampasufile(data, f);
                                fclose(f);
                                printf("Hai eliminato \"%s\"\n", eliminato);
                            }
                            break;
                        }
                    case '2':
                        {
                            printf("Funzione non ancora implementata\n");
                        }
                }
                break;
            }
        case '4':
            {
                do{
                    printf("Inserisci il criterio di ricerca:\n1 - Nome\n2 - Voto\n3 - CFU\n4 - Lodi\n5 - Esami interni/esterni\n");
                    scanf(" %c", &scelta);
                }while(scelta != '1' && scelta != '2' && scelta != '3' && scelta != '4' && scelta != '5');
                switch(scelta){
                    case '1':
                        {
                            printf("Inserisci il nome dell'esame: ");
                            scanf(" %s", nome_esame);
                            puntalista = cercanome(data, nome_esame);
                            if(puntalista == NULL)
                                printf("Nessun esame \"%s\" presente nella lista\n", nome_esame);
                            else{
                            printf("ESAME:\t\tCFU:\t\tVOTO:\t\tInterno/Esterno\n");                                   
                            while(puntalista != NULL){
                                stampaesame(puntalista);
                                puntalista = cercanome(puntalista->next, nome_esame);
                            }
                            }
                            break;
                        }
                    case '2':
                        {                            
                            printf("Inserisci il voto ottenuto: ");
                            scanf(" %d", &risultato);
                            puntalista = cercavoto(data, risultato);
                            if(puntalista == NULL)
                                printf("Nessun esame con voto %d presente nella lista\n", risultato);
                            else{
                            printf("ESAME:\t\tCFU:\t\tVOTO:\t\tInterno/Esterno\n");                                    
                            while(puntalista != NULL){
                                stampaesame(puntalista); 
                                puntalista = cercavoto(puntalista->next, risultato);
                            }
                            } 
                            break;
                        }
                    case '3':
                        {
                            printf("Inserisci il numero di CFU dell'esame: ");
                            scanf(" %d", &peso);
                            puntalista = cercacfu(data, peso);
                            if(puntalista == NULL)
                                printf("Nessun esame da %d CFU presente nella lista\n", peso);
                            else{
                            printf("ESAME:\t\tCFU:\t\tVOTO:\t\tInterno/Esterno\n");                                    
                            while(puntalista != NULL){
                                stampaesame(puntalista); 
                                puntalista = cercacfu(puntalista->next, peso);
                            }
                            } 
                            break;
                        }
                    case '4':
                        {
                            puntalista = cercalodi(data);
                            if(puntalista == NULL)
                                 printf("Nessun esame da 30 e lode presente nella lista\n");
                            else{
                            printf("ESAME:\t\tCFU:\t\tVOTO:\t\tInterno/Esterno\n");                                    
                            while(puntalista != NULL){
                                stampaesame(puntalista); 
                                puntalista = cercacfu(puntalista->next, peso);
                            }
                            }
                            break;
                        }
                    case '5':
                        {
                            do{
                                printf("Vuoi vedere gli esami Interni o quelli Esterni? (i/e): ");
                                scanf(" %c", &scelta);  
                            }while(scelta != 'i' && scelta != 'e');
                            puntalista = data;
                            printf("ESAME:\t\tCFU:\t\tVOTO:\t\tInterno/Esterno\n"); 
                            while(puntalista != NULL){
                                if(scelta == 'i' && puntalista->interno == 's')
                                    stampaesame(puntalista);
                                if(scelta == 'e' && puntalista->interno == 'n')
                                    stampaesame(puntalista);
                                puntalista = puntalista->next;
                            }
                            break;
                        }
                }
                break;
            }
        case '5':
            {
                for(i = 0; i < 3; i++){
                    nlodi = contalodi(data, i);
                    if(i == 0) printf("Complessivamente");
                    if(i == 1) printf("Nei corsi interni");
                    if(i == 2) printf("Nei corsi esterni");
                    printf(" hai %d CFU con una media di %f (con %d lod", sommacfu(data, i), calcolamedia(data, i), nlodi);
                if(nlodi == 1)
                    printf("e)\n");
                else printf("i)\n"); 
                }
                break;
            }
        case 'q':
            {
                continua = 0;
                printf("\nArrivederci\n");
                break;
            }
        case 'Q':
            {
                continua = 0;
                printf("\nArrivederci\n");
                break;
            }
        default: 
            printf("Scelta non valida.\n");
            continue;
    }
    }
    libera(data);
    printf("Ciao Matteo\n");
}
